From 2a1e8b06b48864348d8539cb6bc9e20867a437fa Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Wed, 17 Jan 2001 20:05:08 +0000 Subject: [PATCH] Remove unused variable. Tue Jan 9 11:20:48 2001 Owen Taylor * gdk/x11/gdkdnd-x11.c: Remove unused variable. * gtk/gtkdnd.c: Encapsulate storing and retrieving info structures in functions. Fixes bug where gtk_dataset_* was accidentally still being used in one place, causing every dest side event to be treated independently. * gtk/gtkdnd.c: Remove last vestages of handling ::draw (fixes warning) * gtk/gtkentry.[ch]: Add drag and drop support. * gtk/gtkdnd.[ch] gtk/gtktextview.c gtk/gtkentry.c: Add new function gtk_check_drag_threshhold() for checking to check if (dx,dy) has exceeded the threshhold for starting a drag and use it everywhere. --- gdk/x11/gdkdnd-x11.c | 2 - gtk/gtkdnd.c | 308 +++++++++++++++++++-------------- gtk/gtkdnd.h | 6 + gtk/gtkentry.c | 399 ++++++++++++++++++++++++++++++++++++++----- gtk/gtkentry.h | 6 + gtk/gtktextview.c | 11 +- 6 files changed, 548 insertions(+), 184 deletions(-) diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c index 976abaf3a7..4dc4d3ce98 100644 --- a/gdk/x11/gdkdnd-x11.c +++ b/gdk/x11/gdkdnd-x11.c @@ -2473,8 +2473,6 @@ xdnd_manage_source_filter (GdkDragContext *context, GdkWindow *window, gboolean add_filter) { - gint old_warnings = 0; /* quiet gcc */ - gdk_error_trap_push (); if (!GDK_WINDOW_DESTROYED (window)) diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 0abb2d9d63..78ca1245ef 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -183,39 +183,43 @@ static GdkCursor * gtk_drag_get_cursor (GdkDragAction action); static GtkWidget *gtk_drag_get_ipc_widget (void); static void gtk_drag_release_ipc_widget (GtkWidget *widget); -static void gtk_drag_highlight_paint (GtkWidget *widget); static gboolean gtk_drag_highlight_expose (GtkWidget *widget, GdkEventExpose *event, gpointer data); - -static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget, - GtkDragDestSite *site, - GdkDragContext *context); -static void gtk_drag_selection_received (GtkWidget *widget, - GtkSelectionData *selection_data, - guint32 time, - gpointer data); -static void gtk_drag_find_widget (GtkWidget *widget, - GtkDragFindData *data); -static void gtk_drag_proxy_begin (GtkWidget *widget, - GtkDragDestInfo *dest_info); -static void gtk_drag_dest_info_destroy (gpointer data); -static void gtk_drag_dest_realized (GtkWidget *widget); -static void gtk_drag_dest_site_destroy (gpointer data); -static void gtk_drag_dest_leave (GtkWidget *widget, - GdkDragContext *context, - guint time); -static gboolean gtk_drag_dest_motion (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time); -static gboolean gtk_drag_dest_drop (GtkWidget *widget, - GdkDragContext *context, - gint x, - gint y, - guint time); +static GdkAtom gtk_drag_dest_find_target (GtkWidget *widget, + GtkDragDestSite *site, + GdkDragContext *context); +static void gtk_drag_selection_received (GtkWidget *widget, + GtkSelectionData *selection_data, + guint32 time, + gpointer data); +static void gtk_drag_find_widget (GtkWidget *widget, + GtkDragFindData *data); +static void gtk_drag_proxy_begin (GtkWidget *widget, + GtkDragDestInfo *dest_info, + guint32 time); +static void gtk_drag_dest_realized (GtkWidget *widget); +static void gtk_drag_dest_site_destroy (gpointer data); +static void gtk_drag_dest_leave (GtkWidget *widget, + GdkDragContext *context, + guint time); +static gboolean gtk_drag_dest_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static gboolean gtk_drag_dest_drop (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); + +static GtkDragDestInfo * gtk_drag_get_dest_info (GdkDragContext *context, + gboolean create); +static GtkDragSourceInfo *gtk_drag_get_source_info (GdkDragContext *context, + gboolean create); +static void gtk_drag_clear_source_info (GdkDragContext *context); static void gtk_drag_source_check_selection (GtkDragSourceInfo *info, GdkAtom selection, @@ -239,7 +243,7 @@ static void gtk_drag_selection_get (GtkWidget *widget, gpointer data); static gint gtk_drag_anim_timeout (gpointer data); static void gtk_drag_remove_icon (GtkDragSourceInfo *info); -static void gtk_drag_source_info_destroy (gpointer data); +static void gtk_drag_source_info_destroy (GtkDragSourceInfo *info); static void gtk_drag_update (GtkDragSourceInfo *info, gint x_root, gint y_root, @@ -739,20 +743,22 @@ gtk_drag_finish (GdkDragContext *context, } /************************************************************* - * gtk_drag_highlight_paint: - * Paint a highlight indicating drag status onto the widget. + * gtk_drag_highlight_expose: + * Callback for expose_event for highlighted widgets. * arguments: * widget: + * event: + * data: * results: *************************************************************/ -static void -gtk_drag_highlight_paint (GtkWidget *widget) +static gboolean +gtk_drag_highlight_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer data) { gint x, y, width, height; - - g_return_if_fail (widget != NULL); - + if (GTK_WIDGET_DRAWABLE (widget)) { if (GTK_WIDGET_NO_WINDOW (widget)) @@ -778,24 +784,7 @@ gtk_drag_highlight_paint (GtkWidget *widget) FALSE, x, y, width - 1, height - 1); } -} -/************************************************************* - * gtk_drag_highlight_expose: - * Callback for expose_event for highlighted widgets. - * arguments: - * widget: - * event: - * data: - * results: - *************************************************************/ - -static gboolean -gtk_drag_highlight_expose (GtkWidget *widget, - GdkEventExpose *event, - gpointer data) -{ - gtk_drag_highlight_paint (widget); return TRUE; } @@ -830,9 +819,6 @@ gtk_drag_unhighlight (GtkWidget *widget) { g_return_if_fail (widget != NULL); - gtk_signal_disconnect_by_func (GTK_OBJECT (widget), - GTK_SIGNAL_FUNC (gtk_drag_highlight_paint), - NULL); gtk_signal_disconnect_by_func (GTK_OBJECT (widget), GTK_SIGNAL_FUNC (gtk_drag_highlight_expose), NULL); @@ -980,21 +966,7 @@ gtk_drag_dest_handle_event (GtkWidget *toplevel, context = event->dnd.context; - info = g_dataset_get_data (context, "gtk-info"); - if (!info) - { - info = g_new (GtkDragDestInfo, 1); - info->widget = NULL; - info->context = event->dnd.context; - info->proxy_source = NULL; - info->proxy_data = NULL; - info->dropped = FALSE; - info->proxy_drop_wait = FALSE; - g_object_set_qdata_full (G_OBJECT (context), - g_quark_from_static_string ("gtk-info"), - info, - gtk_drag_dest_info_destroy); - } + info = gtk_drag_get_dest_info (context, TRUE); /* Find the widget for the event */ switch (event->type) @@ -1124,7 +1096,7 @@ gtk_drag_selection_received (GtkWidget *widget, drop_widget = data; context = gtk_object_get_data (GTK_OBJECT (widget), "drag-context"); - info = g_object_get_qdata (G_OBJECT (context), g_quark_from_static_string ("gtk-info")); + info = gtk_drag_get_dest_info (context, FALSE); if (info->proxy_data && info->proxy_data->target == selection_data->target) @@ -1318,18 +1290,29 @@ gtk_drag_find_widget (GtkWidget *widget, static void gtk_drag_proxy_begin (GtkWidget *widget, - GtkDragDestInfo *dest_info) + GtkDragDestInfo *dest_info, + guint32 time) { GtkDragSourceInfo *source_info; GList *tmp_list; + GdkDragContext *context; + GtkWidget *ipc_widget; + + if (dest_info->proxy_source) + { + gdk_drag_abort (dest_info->proxy_source->context, time); + gtk_drag_source_info_destroy (dest_info->proxy_source); + dest_info->proxy_source = NULL; + } - source_info = g_new0 (GtkDragSourceInfo, 1); - source_info->ipc_widget = gtk_drag_get_ipc_widget (); - - source_info->widget = widget; - gtk_widget_ref (source_info->widget); - source_info->context = gdk_drag_begin (source_info->ipc_widget->window, - dest_info->context->targets); + ipc_widget = gtk_drag_get_ipc_widget (); + context = gdk_drag_begin (ipc_widget->window, + dest_info->context->targets); + + source_info = gtk_drag_get_source_info (context, TRUE); + + source_info->ipc_widget = ipc_widget; + source_info->widget = gtk_widget_ref (widget); source_info->target_list = gtk_target_list_new (NULL, 0); tmp_list = dest_info->context->targets; @@ -1342,11 +1325,7 @@ gtk_drag_proxy_begin (GtkWidget *widget, source_info->proxy_dest = dest_info; - g_object_set_qdata (G_OBJECT (source_info->context), - g_quark_from_static_string ("gtk-info"), - source_info); - - gtk_signal_connect (GTK_OBJECT (source_info->ipc_widget), + gtk_signal_connect (GTK_OBJECT (ipc_widget), "selection_get", GTK_SIGNAL_FUNC (gtk_drag_selection_get), source_info); @@ -1362,6 +1341,59 @@ gtk_drag_dest_info_destroy (gpointer data) g_free (info); } +static GtkDragDestInfo * +gtk_drag_get_dest_info (GdkDragContext *context, + gboolean create) +{ + GtkDragDestInfo *info; + static GQuark info_quark = 0; + if (!info_quark) + info_quark = g_quark_from_static_string ("gtk-dest-info"); + + info = g_object_get_qdata (G_OBJECT (context), info_quark); + if (!info && create) + { + info = g_new (GtkDragDestInfo, 1); + info->widget = NULL; + info->context = context; + info->proxy_source = NULL; + info->proxy_data = NULL; + info->dropped = FALSE; + info->proxy_drop_wait = FALSE; + g_object_set_qdata_full (G_OBJECT (context), info_quark, + info, gtk_drag_dest_info_destroy); + } + + return info; +} + +static GQuark dest_info_quark = 0; + +static GtkDragSourceInfo * +gtk_drag_get_source_info (GdkDragContext *context, + gboolean create) +{ + GtkDragSourceInfo *info; + if (!dest_info_quark) + dest_info_quark = g_quark_from_static_string ("gtk-source-info"); + + info = g_object_get_qdata (G_OBJECT (context), dest_info_quark); + if (!info && create) + { + info = g_new0 (GtkDragSourceInfo, 1); + info->context = context; + g_object_set_qdata (G_OBJECT (context), dest_info_quark, info); + } + + return info; +} + +static void +gtk_drag_clear_source_info (GdkDragContext *context) +{ + g_object_set_qdata (G_OBJECT (context), dest_info_quark, NULL); +} + static void gtk_drag_dest_realized (GtkWidget *widget) { @@ -1395,11 +1427,14 @@ gtk_drag_dest_leave (GtkWidget *widget, if (site->do_proxy) { - GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context), - g_quark_from_static_string ("gtk-info")); + GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE); - if (info->proxy_source && !info->dropped) - gdk_drag_abort (info->proxy_source->context, time); + if (info->proxy_source && info->proxy_source->widget == widget && !info->dropped) + { + gdk_drag_abort (info->proxy_source->context, time); + gtk_drag_source_info_destroy (info->proxy_source); + info->proxy_source = NULL; + } return; } @@ -1437,11 +1472,10 @@ gtk_drag_dest_motion (GtkWidget *widget, GdkWindow *dest_window; GdkDragProtocol proto; - GtkDragDestInfo *info = g_object_get_qdata (G_OBJECT (context), - g_quark_from_static_string ("gtk-info")); + GtkDragDestInfo *info = gtk_drag_get_dest_info (context, FALSE); - if (!info->proxy_source) - gtk_drag_proxy_begin (widget, info); + if (!info->proxy_source || info->proxy_source->widget != widget) + gtk_drag_proxy_begin (widget, info, time); current_event = gtk_get_current_event (); @@ -1535,8 +1569,7 @@ gtk_drag_dest_drop (GtkWidget *widget, site = gtk_object_get_data (GTK_OBJECT (widget), "gtk-drag-dest"); g_return_val_if_fail (site != NULL, FALSE); - info = g_object_get_qdata (G_OBJECT (context), - g_quark_from_static_string ("gtk-info")); + info = gtk_drag_get_dest_info (context, FALSE); g_return_val_if_fail (info != NULL, FALSE); info->drop_x = x; @@ -1560,7 +1593,7 @@ gtk_drag_dest_drop (GtkWidget *widget, GdkWindow *dest_window; GdkDragProtocol proto; - gtk_drag_proxy_begin (widget, info); + gtk_drag_proxy_begin (widget, info, time); info->proxy_drop_wait = TRUE; info->proxy_drop_time = time; @@ -1596,7 +1629,6 @@ gtk_drag_dest_drop (GtkWidget *widget, gtk_drag_source_check_selection (info->proxy_source, selection, time); gdk_event_free (current_event); - } return TRUE; @@ -1650,6 +1682,8 @@ gtk_drag_begin (GtkWidget *widget, GList *tmp_list; guint32 time = GDK_CURRENT_TIME; GdkDragAction possible_actions, suggested_action; + GdkDragContext *context; + GtkWidget *ipc_widget; g_return_val_if_fail (widget != NULL, NULL); g_return_val_if_fail (GTK_WIDGET_REALIZED (widget), NULL); @@ -1658,12 +1692,6 @@ gtk_drag_begin (GtkWidget *widget, if (event) time = gdk_event_get_time (event); - info = g_new0 (GtkDragSourceInfo, 1); - info->ipc_widget = gtk_drag_get_ipc_widget (); - source_widgets = g_slist_prepend (source_widgets, info->ipc_widget); - - gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info); - tmp_list = g_list_last (target_list->list); while (tmp_list) { @@ -1673,15 +1701,20 @@ gtk_drag_begin (GtkWidget *widget, tmp_list = tmp_list->prev; } - info->widget = widget; - gtk_widget_ref (info->widget); - - info->context = gdk_drag_begin (info->ipc_widget->window, targets); + ipc_widget = gtk_drag_get_ipc_widget (); + source_widgets = g_slist_prepend (source_widgets, ipc_widget); + + context = gdk_drag_begin (ipc_widget->window, targets); g_list_free (targets); - g_object_set_qdata (G_OBJECT (info->context), - g_quark_from_static_string ("gtk-info"), info); + info = gtk_drag_get_source_info (context, TRUE); + + info->ipc_widget = ipc_widget; + gtk_object_set_data (GTK_OBJECT (info->ipc_widget), "gtk-info", info); + + info->widget = gtk_widget_ref (widget); + info->button = button; info->target_list = target_list; gtk_target_list_ref (target_list); @@ -1916,8 +1949,7 @@ gtk_drag_set_icon_window (GdkDragContext *context, g_return_if_fail (context != NULL); g_return_if_fail (widget != NULL); - info = g_object_get_qdata (G_OBJECT (context), - g_quark_from_static_string ("gtk-info")); + info = gtk_drag_get_source_info (context, FALSE); gtk_drag_remove_icon (info); info->icon_window = widget; @@ -2108,8 +2140,7 @@ gtk_drag_source_handle_event (GtkWidget *widget, g_return_if_fail (event != NULL); context = event->dnd.context; - info = g_object_get_qdata (G_OBJECT (context), - g_quark_from_static_string ("gtk-info")); + info = gtk_drag_get_source_info (context, FALSE); if (!info) return; @@ -2288,8 +2319,7 @@ gtk_drag_drop_finished (GtkDragSourceInfo *info, /* Mark the context as dead, so if the destination decides * to respond really late, we still are OK. */ - g_object_set_qdata (G_OBJECT (info->context), - g_quark_from_static_string ("gtk-info"), NULL); + gtk_drag_clear_source_info (info->context); gtk_timeout_add (ANIM_STEP_TIME, gtk_drag_anim_timeout, anim); } } @@ -2410,9 +2440,9 @@ gtk_drag_source_event_cb (GtkWidget *widget, GDK_BUTTON1_MASK << (i - 1)) break; } - - if (MAX (ABS (site->x - event->motion.x), - ABS (site->y - event->motion.y)) > 3) + + if (gtk_drag_check_threshold (widget, site->x, site->y, + event->motion.x, event->motion.y)) { GtkDragSourceInfo *info; GdkDragContext *context; @@ -2422,10 +2452,7 @@ gtk_drag_source_event_cb (GtkWidget *widget, site->actions, i, event); - - info = g_object_get_qdata (G_OBJECT (context), - g_quark_from_static_string ("gtk-info")); - + info = gtk_drag_get_source_info (context, FALSE); if (!info->icon_window) { if (site->pixmap) @@ -2578,11 +2605,9 @@ gtk_drag_remove_icon (GtkDragSourceInfo *info) } static void -gtk_drag_source_info_destroy (gpointer data) +gtk_drag_source_info_destroy (GtkDragSourceInfo *info) { - GtkDragSourceInfo *info = data; - - gtk_drag_remove_icon (data); + gtk_drag_remove_icon (info); if (!info->proxy_dest) gtk_signal_emit_by_name (GTK_OBJECT (info->widget), "drag_end", @@ -2599,7 +2624,7 @@ gtk_drag_source_info_destroy (gpointer data) gtk_target_list_unref (info->target_list); - g_object_set_qdata (G_OBJECT (info->context), g_quark_from_static_string ("gtk-info"), NULL); + gtk_drag_clear_source_info (info->context); gdk_drag_context_unref (info->context); if (info->drop_timeout) @@ -2854,3 +2879,30 @@ gtk_drag_abort_timeout (gpointer data) return FALSE; } + +/** + * gtk_drag_check_threshold: + * @widget: a #GtkWidget + * @start_x: X coordinate of start of drag + * @start_y: Y coordinate of start of drag + * @current_x: current X coordinate + * @current_y: current Y coordinate + * + * Checks to see if a mouse drag starting at (start_x, start_y) and ending + * at (current_x, current_y) has passed the GTK drag threshhold, and thus + * should trigger the beginning of a drag-and-drop operation. + * + * Return Value: If the drag threshold has been passed. + **/ +gboolean +gtk_drag_check_threshold (GtkWidget *widget, + gint start_x, + gint start_y, + gint current_x, + gint current_y) +{ +#define DRAG_THRESHOLD 8 + + return (ABS (current_x - start_x) > DRAG_THRESHOLD || + ABS (current_y - start_y) > DRAG_THRESHOLD); +} diff --git a/gtk/gtkdnd.h b/gtk/gtkdnd.h index 84e7da2c52..e1c23b942b 100644 --- a/gtk/gtkdnd.h +++ b/gtk/gtkdnd.h @@ -131,6 +131,12 @@ void gtk_drag_set_default_icon (GdkColormap *colormap, gint hot_y); +gboolean gtk_drag_check_threshold (GtkWidget *widget, + gint start_x, + gint start_y, + gint current_x, + gint current_y); + /* Internal functions */ void gtk_drag_source_handle_event (GtkWidget *widget, GdkEvent *event); diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index f2edb59daa..ecfcb86a83 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -31,6 +31,7 @@ #include "gdk/gdkkeysyms.h" #include "gtkbindings.h" #include "gtkclipboard.h" +#include "gtkdnd.h" #include "gtkentry.h" #include "gtkimmulticontext.h" #include "gtkintl.h" @@ -76,6 +77,19 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; +typedef enum { + CURSOR_STANDARD, + CURSOR_DND +} CursorType; + +static GtkTargetEntry target_table[] = { + { "UTF8_STRING", 0, 0 }, + { "COMPOUND_TEXT", 0, 0 }, + { "TEXT", 0, 0 }, + { "text/plain", 0, 0 }, + { "STRING", 0, 0 } +}; + /* GObject, GtkObject methods */ static void gtk_entry_class_init (GtkEntryClass *klass); @@ -119,6 +133,29 @@ static void gtk_entry_direction_changed (GtkWidget *widget, static void gtk_entry_state_changed (GtkWidget *widget, GtkStateType previous_state); +static gboolean gtk_entry_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); +static void gtk_entry_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time); +static void gtk_entry_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time); +static void gtk_entry_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time); +static void gtk_entry_drag_data_delete (GtkWidget *widget, + GdkDragContext *context); + /* GtkEditable method implementations */ static void gtk_entry_insert_text (GtkEditable *editable, @@ -174,7 +211,8 @@ static void gtk_entry_preedit_changed_cb (GtkIMContext *context, /* Internal routines */ static void gtk_entry_draw_text (GtkEntry *entry); -static void gtk_entry_draw_cursor (GtkEntry *entry); +static void gtk_entry_draw_cursor (GtkEntry *entry, + CursorType type); static PangoLayout *gtk_entry_get_layout (GtkEntry *entry, gboolean include_preedit); static void gtk_entry_queue_draw (GtkEntry *entry); @@ -183,6 +221,7 @@ static void gtk_entry_recompute (GtkEntry *entry); static gint gtk_entry_find_position (GtkEntry *entry, gint x); static void gtk_entry_get_cursor_locations (GtkEntry *entry, + CursorType type, gint *strong_x, gint *weak_x); static void gtk_entry_adjust_scroll (GtkEntry *entry); @@ -298,6 +337,12 @@ gtk_entry_class_init (GtkEntryClass *class) widget_class->direction_changed = gtk_entry_direction_changed; widget_class->state_changed = gtk_entry_state_changed; + widget_class->drag_motion = gtk_entry_drag_motion; + widget_class->drag_leave = gtk_entry_drag_leave; + widget_class->drag_data_received = gtk_entry_drag_data_received; + widget_class->drag_data_get = gtk_entry_drag_data_get; + widget_class->drag_data_delete = gtk_entry_drag_data_delete; + class->insert_text = gtk_entry_real_insert_text; class->delete_text = gtk_entry_real_delete_text; class->move_cursor = gtk_entry_move_cursor; @@ -629,7 +674,13 @@ gtk_entry_init (GtkEntry *entry) entry->editable = TRUE; entry->visible = TRUE; entry->invisible_char = '*'; + entry->dnd_position = -1; + gtk_drag_dest_set (GTK_WIDGET (entry), + GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_HIGHLIGHT, + target_table, G_N_ELEMENTS (target_table), + GDK_ACTION_COPY | GDK_ACTION_MOVE); + /* This object is completely private. No external entity can gain a reference * to it; so we create it here and destroy it in finalize(). */ @@ -883,7 +934,14 @@ gtk_entry_expose (GtkWidget *widget, else if (entry->text_area == event->window) { gtk_entry_draw_text (GTK_ENTRY (widget)); - gtk_entry_draw_cursor (GTK_ENTRY (widget)); + + if ((entry->visible || entry->invisible_char != 0) && + GTK_WIDGET_HAS_FOCUS (widget) && + entry->selection_bound == entry->current_pos) + gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_STANDARD); + + if (entry->dnd_position != -1) + gtk_entry_draw_cursor (GTK_ENTRY (widget), CURSOR_DND); } return FALSE; @@ -896,6 +954,7 @@ gtk_entry_button_press (GtkWidget *widget, GtkEntry *entry = GTK_ENTRY (widget); GtkEditable *editable = GTK_EDITABLE (widget); gint tmp_pos; + gint sel_start, sel_end; entry = GTK_ENTRY (widget); editable = GTK_EDITABLE (widget); @@ -916,12 +975,26 @@ gtk_entry_button_press (GtkWidget *widget, switch (event->type) { case GDK_BUTTON_PRESS: - gtk_entry_reset_im_context (entry); - - entry->current_pos = tmp_pos; - entry->selection_bound = tmp_pos; + if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end) && + tmp_pos >= sel_start && tmp_pos <= sel_end) + { + /* Click inside the selection - we'll either start a drag, or + * clear the selection + */ - gtk_entry_recompute (entry); + entry->in_drag = TRUE; + entry->drag_start_x = event->x + entry->scroll_offset; + entry->drag_start_y = event->y + entry->scroll_offset; + } + else + { + gtk_entry_reset_im_context (entry); + + entry->current_pos = tmp_pos; + entry->selection_bound = tmp_pos; + + gtk_entry_recompute (entry); + } break; @@ -962,13 +1035,28 @@ gtk_entry_button_release (GtkWidget *widget, GdkEventButton *event) { GtkEntry *entry = GTK_ENTRY (widget); - GtkEditable *editable = GTK_EDITABLE (widget); if (event->window != entry->text_area || entry->button != event->button) return FALSE; + if (entry->in_drag) + { + gint tmp_pos = gtk_entry_find_position (entry, entry->drag_start_x); + + gtk_entry_reset_im_context (entry); + + entry->current_pos = tmp_pos; + entry->selection_bound = tmp_pos; + + gtk_entry_recompute (entry); + + entry->in_drag = 0; + } + entry->button = 0; + gtk_entry_update_primary_selection (entry); + return FALSE; } @@ -985,12 +1073,35 @@ gtk_entry_motion_notify (GtkWidget *widget, if (event->is_hint || (entry->text_area != event->window)) gdk_window_get_pointer (entry->text_area, NULL, NULL, NULL); - tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); + if (entry->in_drag) + { + if (gtk_drag_check_threshold (widget, + entry->drag_start_x, entry->drag_start_y, + event->x + entry->scroll_offset, event->y)) + { + GdkDragContext *context; + GtkTargetList *target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table)); + + context = gtk_drag_begin (widget, target_list, GDK_ACTION_COPY | GDK_ACTION_MOVE, + entry->button, (GdkEvent *)event); - if (tmp_pos != entry->current_pos) + + entry->in_drag = FALSE; + entry->button = 0; + + gtk_target_list_unref (target_list); + gtk_drag_set_icon_default (context); + } + } + else { - entry->current_pos = tmp_pos; - gtk_entry_recompute (entry); + tmp_pos = gtk_entry_find_position (entry, event->x + entry->scroll_offset); + + if (tmp_pos != entry->current_pos) + { + entry->current_pos = tmp_pos; + gtk_entry_recompute (entry); + } } return TRUE; @@ -1241,6 +1352,43 @@ gtk_entry_style_set (GtkWidget *widget, } } +static char * +strstr_len (const char *haystack, + int haystack_len, + const char *needle) +{ + int i; + + g_return_val_if_fail (haystack != NULL, NULL); + g_return_val_if_fail (needle != NULL, NULL); + + if (haystack_len < 0) + return strstr (haystack, needle); + else + { + const char *p = haystack; + int needle_len = strlen (needle); + const char *end = haystack + haystack_len - needle_len; + + if (needle_len == 0) + return (char *)haystack; + + while (*p && p <= end) + { + for (i = 0; i < needle_len; i++) + if (p[i] != needle[i]) + goto next; + + return (char *)p; + + next: + p += needle_len; + } + } + + return NULL; +} + /* Default signal handlers */ static void @@ -1251,10 +1399,26 @@ gtk_entry_real_insert_text (GtkEntry *entry, { gint index; gint n_chars; + gchar line_separator[7]; + gint len; + gchar *p; if (new_text_length < 0) new_text_length = strlen (new_text); + /* We don't want to allow inserting paragraph delimeters + */ + pango_find_paragraph_boundary (new_text, new_text_length, &new_text_length, NULL); + + /* Or line separators - this is really painful + */ + len = g_unichar_to_utf8 (0x2028, line_separator); /* 0x2028 == LS */ + line_separator[len] = '\0'; + + p = strstr_len (new_text, new_text_length, line_separator); + if (p) + new_text_length = p - new_text; + n_chars = g_utf8_strlen (new_text, new_text_length); if (entry->text_max_length > 0 && n_chars + entry->text_length > entry->text_max_length) { @@ -1807,39 +1971,32 @@ gtk_entry_draw_text (GtkEntry *entry) } static void -gtk_entry_draw_cursor (GtkEntry *entry) +gtk_entry_draw_cursor (GtkEntry *entry, + CursorType type) { g_return_if_fail (entry != NULL); g_return_if_fail (GTK_IS_ENTRY (entry)); - if (!entry->visible && entry->invisible_char == 0) - return; - if (GTK_WIDGET_DRAWABLE (entry)) { GtkWidget *widget = GTK_WIDGET (entry); - if (GTK_WIDGET_HAS_FOCUS (widget) && - (entry->selection_bound == entry->current_pos)) - { - gint xoffset = INNER_BORDER - entry->scroll_offset; - gint strong_x, weak_x; - gint text_area_height; - - gdk_window_get_size (entry->text_area, NULL, &text_area_height); + gint xoffset = INNER_BORDER - entry->scroll_offset; + gint strong_x, weak_x; + gint text_area_height; - gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x); - - gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED], - xoffset + strong_x, INNER_BORDER, - xoffset + strong_x, text_area_height - INNER_BORDER); - - if (weak_x != strong_x) - gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL], - xoffset + weak_x, INNER_BORDER, - xoffset + weak_x, text_area_height - INNER_BORDER); - - } + gdk_window_get_size (entry->text_area, NULL, &text_area_height); + + gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x); + + gdk_draw_line (entry->text_area, widget->style->bg_gc[GTK_STATE_SELECTED], + xoffset + strong_x, INNER_BORDER, + xoffset + strong_x, text_area_height - INNER_BORDER); + + if (weak_x != strong_x) + gdk_draw_line (entry->text_area, widget->style->fg_gc[GTK_STATE_NORMAL], + xoffset + weak_x, INNER_BORDER, + xoffset + weak_x, text_area_height - INNER_BORDER); } } @@ -1906,22 +2063,28 @@ gtk_entry_find_position (GtkEntry *entry, } static void -gtk_entry_get_cursor_locations (GtkEntry *entry, - gint *strong_x, - gint *weak_x) +gtk_entry_get_cursor_locations (GtkEntry *entry, + CursorType type, + gint *strong_x, + gint *weak_x) { PangoLayout *layout = gtk_entry_get_layout (entry, TRUE); const gchar *text; PangoRectangle strong_pos, weak_pos; gint index; - text = pango_layout_get_text (layout); - - index = - g_utf8_offset_to_pointer (text, - entry->current_pos + - entry->preedit_cursor) - text; - + if (type == CURSOR_STANDARD) + { + text = pango_layout_get_text (layout); + index = g_utf8_offset_to_pointer (text, entry->current_pos + entry->preedit_cursor) - text; + } + else /* type == CURSOR_DND */ + { + index = g_utf8_offset_to_pointer (entry->text, entry->dnd_position) - entry->text; + if (entry->dnd_position > entry->current_pos) + index += entry->preedit_length; + } + pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos); g_object_unref (G_OBJECT (layout)); @@ -1990,7 +2153,7 @@ gtk_entry_adjust_scroll (GtkEntry *entry) * put the weak cursor on screen if possible. */ - gtk_entry_get_cursor_locations (entry, &strong_x, &weak_x); + gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, &weak_x); strong_xoffset = strong_x - entry->scroll_offset; @@ -2482,3 +2645,145 @@ gtk_entry_popup_menu (GtkEntry *entry, NULL, NULL, event->button, event->time); } + +static void +gtk_entry_drag_leave (GtkWidget *widget, + GdkDragContext *context, + guint time) +{ + GtkEntry *entry; + + entry = GTK_ENTRY (widget); + + entry->dnd_position = -1; + gtk_widget_queue_draw (widget); +} + +static gboolean +gtk_entry_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + GtkEntry *entry; + GtkWidget *source_widget; + GdkDragAction suggested_action; + gint new_position, old_position; + gint sel1, sel2; + + entry = GTK_ENTRY (widget); + + x -= widget->style->xthickness; + y -= widget->style->ythickness; + + old_position = entry->dnd_position; + new_position = gtk_entry_find_position (entry, x + entry->scroll_offset); + + source_widget = gtk_drag_get_source_widget (context); + suggested_action = context->suggested_action; + + if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &sel1, &sel2) || + new_position < sel1 || new_position > sel2) + { + if (source_widget == widget) + { + /* Default to MOVE, unless the user has + * pressed ctrl or alt to affect available actions + */ + if ((context->actions & GDK_ACTION_MOVE) != 0) + suggested_action = GDK_ACTION_MOVE; + } + + entry->dnd_position = new_position; + } + else + { + if (source_widget == widget) + suggested_action = 0; /* Can't drop in selection where drag started */ + + entry->dnd_position = -1; + } + + gdk_drag_status (context, suggested_action, time); + + if (entry->dnd_position != old_position) + gtk_widget_queue_draw (widget); + + return TRUE; +} + +static void +gtk_entry_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + GtkEntry *entry; + GtkEditable *editable; + gchar *str; + + entry = GTK_ENTRY (widget); + editable = GTK_EDITABLE (widget); + + str = gtk_selection_data_get_text (selection_data); + + if (str) + { + gint new_position; + gint sel1, sel2; + + new_position = gtk_entry_find_position (entry, x + entry->scroll_offset); + + if (!gtk_editable_get_selection_bounds (editable, &sel1, &sel2) || + new_position < sel1 || new_position > sel2) + { + gtk_editable_insert_text (editable, str, -1, &new_position); + } + else + { + /* Replacing selection */ + gtk_editable_delete_text (editable, sel1, sel2); + gtk_editable_insert_text (editable, str, -1, &sel1); + } + + g_free (str); + } +} + +static void +gtk_entry_drag_data_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + gint sel_start, sel_end; + + GtkEditable *editable = GTK_EDITABLE (widget); + + if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end)) + { + gchar *str = gtk_editable_get_chars (editable, sel_start, sel_end); + + gtk_selection_data_set_text (selection_data, str); + + g_free (str); + } + +} + +static void +gtk_entry_drag_data_delete (GtkWidget *widget, + GdkDragContext *context) +{ + gint sel_start, sel_end; + + GtkEditable *editable = GTK_EDITABLE (widget); + + if (gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end)) + gtk_editable_delete_text (editable, sel_start, sel_end); +} diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h index 6099ac13bc..553837603d 100644 --- a/gtk/gtkentry.h +++ b/gtk/gtkentry.h @@ -58,6 +58,7 @@ struct _GtkEntry guint editable : 1; guint visible : 1; guint overwrite_mode : 1; + guint in_drag : 1; /* Dragging within the selection */ guint16 text_length; /* length in use, in chars */ guint16 text_max_length; @@ -87,6 +88,11 @@ struct _GtkEntry guint16 preedit_length; /* length of preedit string, in bytes */ guint16 preedit_cursor; /* offset of cursor within preedit string, in chars */ + + gint dnd_position; /* In chars, -1 == no DND cursor */ + + gint drag_start_x; + gint drag_start_y; gunichar invisible_char; }; diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 8d567e4dde..d1e21374ec 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -76,7 +76,6 @@ */ #define FOCUS_EDGE_WIDTH 1 -#define DRAG_THRESHOLD 8 #define SCREEN_WIDTH(widget) text_window_get_width (GTK_TEXT_VIEW (widget)->text_window) #define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->text_window) @@ -3204,16 +3203,14 @@ gtk_text_view_motion_event (GtkWidget *widget, GdkEventMotion *event) text_view->drag_start_x >= 0) { gint x, y; - gint dx, dy; gdk_window_get_pointer (text_view->text_window->bin_window, &x, &y, NULL); - dx = text_view->drag_start_x - x; - dy = text_view->drag_start_y - y; - - if (ABS (dx) > DRAG_THRESHOLD || - ABS (dy) > DRAG_THRESHOLD) + if (gtk_drag_check_threshold (widget, + text_view->drag_start_x, + text_view->drag_start_y, + x, y)) { GtkTextIter iter; gint buffer_x, buffer_y; -- 2.30.2